package com.zyk.scaffold.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyk.scaffold.core.domain.PageFilter;
import com.zyk.scaffold.core.domain.PageResult;
import com.zyk.scaffold.common.enums.TenantRoleTypeEnum;
import com.zyk.scaffold.common.utils.AssertUtil;
import com.zyk.scaffold.common.utils.BeanCopyUtil;
import com.zyk.scaffold.user.controller.tenantrole.*;
import com.zyk.scaffold.user.domain.FunctionMessage;
import com.zyk.scaffold.user.entity.*;
import com.zyk.scaffold.user.mapper.TenantRoleMapper;
import com.zyk.scaffold.user.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户-角色表 服务实现类
 * </p>
 *
 * @author zhouyk
 * @since 2021-12-06
 */
@Service
public class TenantRoleServiceImpl extends ServiceImpl<TenantRoleMapper, TenantRole> implements TenantRoleService {
    @Autowired
    private TenantRoleMapper tenantRoleMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private FunctionService functionService;

    @Autowired
    private TenantFunctionService tenantFunctionService;

    @Autowired
    private TenantUserRoleService userRoleService;

    @Autowired
    private TenantRoleFunctionService tenantRoleFunctionService;

    @Override
    public List<TenantRole> getRolesByIds(List<Long> roleIds, String tenantCode) {
        if(CollectionUtils.isEmpty(roleIds)){
            return Collections.EMPTY_LIST;
        }
        QueryWrapper<TenantRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(TenantRole::getDeleted, Boolean.FALSE)
                .eq(TenantRole::getTenantCode, tenantCode)
                .in(TenantRole::getId, roleIds);
        return tenantRoleMapper.selectList(queryWrapper);
    }

    @Override
    public Boolean newRole(TenantRoleNewRequ tenantRoleNewRequ, Long userId, String tenantCode) {
        QueryWrapper<TenantRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(TenantRole::getDeleted, Boolean.FALSE)
                .eq(TenantRole::getTenantCode, tenantCode)
                .eq(TenantRole::getName, tenantRoleNewRequ.getName());
        List<TenantRole> tenantRoles = tenantRoleMapper.selectList(queryWrapper);

        AssertUtil.isEmptyCollection(tenantRoles, "该角色名称已存在");

        TenantRole tenantRole = BeanCopyUtil.copyProperties(tenantRoleNewRequ, TenantRole::new);
        tenantRole.setCreateUser(userId);
        tenantRole.setUpdateUser(userId);
        tenantRole.setType(TenantRoleTypeEnum.TENANT_ROLE_TYPE_BUSINESS.getCode());
        tenantRole.setTenantCode(tenantCode);
        boolean save = save(tenantRole);
        List<Long> tenantFunctionIds = tenantRoleNewRequ.getTenantFunctionIds();
        if(CollectionUtils.isNotEmpty(tenantFunctionIds)){
            Long id = tenantRole.getId();
            saveRoleFunction(tenantFunctionIds, id, userId, tenantCode);
        }
        return save;
    }

    @Override
    public PageResult<TenantRoleInfosResp> pageFilterRole(PageFilter<TenantRolePageFilterRequ> pageFilter, String tenantCode) {
        TenantRolePageFilterRequ filter = pageFilter.getFilter();
        QueryWrapper<TenantRole> pageFilterQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<TenantRole> lambda = pageFilterQueryWrapper.lambda();
        if(null != filter){
            if(StringUtils.isNotEmpty(filter.getName())){
                lambda.likeRight(TenantRole::getName, filter.getName());
            }
        }
        lambda.eq(TenantRole::getType, TenantRoleTypeEnum.TENANT_ROLE_TYPE_BUSINESS.getCode());
        lambda.eq(TenantRole::getDeleted, Boolean.FALSE);
        lambda.eq(TenantRole::getTenantCode, tenantCode);

        Page<User> page = tenantRoleMapper.selectPage(pageFilter.toPage(), pageFilterQueryWrapper);
        PageResult<TenantRoleInfosResp> pageResult = PageResult.build(page, TenantRoleInfosResp::new);
        List<TenantRoleInfosResp> records = pageResult.getRecords();

        List<Long> roleIds = records.stream().map(TenantRoleInfosResp::getId).collect(Collectors.toList());
        List<TenantRoleFunction> tenantRoleFunctions = tenantRoleFunctionService.getRoleFunctionsByRoleIds(roleIds);

        List<FunctionMessage> functionMessages = tenantFunctionService.queryTenantCodesFunction(Arrays.asList(tenantCode));
        Map<Long, String> mapTenantFunctionId2FunctionName = functionMessages.stream().collect(Collectors.toMap(FunctionMessage::getTenantFunctionId, FunctionMessage::getName, (a, b) -> a));

        Map<Long, List<Long>> mapRoleId2TenantFunctionIds = tenantRoleFunctions.stream()
                .filter(item -> mapTenantFunctionId2FunctionName.containsKey(item.getTenantFunctionId()))
                .collect(Collectors.groupingBy(TenantRoleFunction::getTenantRoleId, Collectors.mapping(TenantRoleFunction::getTenantFunctionId, Collectors.toList())));

        ArrayList<Long> optionUserIds = new ArrayList<>();
        optionUserIds.addAll(records.stream().map(TenantRoleInfosResp::getCreateUser).collect(Collectors.toList()));
        optionUserIds.addAll(records.stream().map(TenantRoleInfosResp::getUpdateUser).collect(Collectors.toList()));

        Map<Long, String> mapUserId2Name;
        if (CollectionUtils.isNotEmpty(optionUserIds)) {
            mapUserId2Name = userService.listByIds(optionUserIds).stream()
                    .collect(Collectors.toMap(User::getId, User::getName, (a, b) -> a));
        } else {
            mapUserId2Name = new HashMap<>();
        }


        for (TenantRoleInfosResp record : records) {
            Long id = record.getId();
            List<Long> tenantFunctionIds = mapRoleId2TenantFunctionIds.get(id);
            if(null == tenantFunctionIds){
                tenantFunctionIds = Collections.EMPTY_LIST;
            }
            record.setTenantFunctionIds(tenantFunctionIds);
            List<String> functionNames = tenantFunctionIds.stream().map(mapTenantFunctionId2FunctionName::get).collect(Collectors.toList());
            record.setFunctionNames(functionNames);
            record.setCreateUserName(mapUserId2Name.get(record.getCreateUser()));
            record.setUpdateUserName(mapUserId2Name.get(record.getUpdateUser()));
        }
        return pageResult;
    }

    @Override
    public List<TenantRoleInfosResp> listRoleAll(String tenantCode) {
        QueryWrapper<TenantRole> deptQueryWrapper = new QueryWrapper<>();
        deptQueryWrapper.lambda()
                .eq(TenantRole::getTenantCode, tenantCode)
                .eq(TenantRole::getDeleted, Boolean.FALSE);
        List<TenantRole> list = list(deptQueryWrapper);
        List<TenantRoleInfosResp> listResps = BeanCopyUtil.copyListProperties(list, TenantRoleInfosResp::new);
        if(listResps == null){
            return Collections.emptyList();
        }
        return listResps;
    }

    @Override
    public Boolean editedRole(TenantRoleEditedRequ tenantRoleEditedRequ, Long userId, String tenantCode) {
        QueryWrapper<TenantRole> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(TenantRole::getDeleted, Boolean.FALSE)
                .eq(TenantRole::getTenantCode, tenantCode)
                .eq(TenantRole::getName, tenantRoleEditedRequ.getName())
                .ne(TenantRole::getId, tenantRoleEditedRequ.getId());
        List<TenantRole> tenantRoles = tenantRoleMapper.selectList(queryWrapper);
        AssertUtil.isEmptyCollection(tenantRoles, "该角色名称已存在");

        TenantRole tenantRole = this.getById(tenantRoleEditedRequ.getId());
        AssertUtil.notIsNull(tenantRole, "角色不存在");
        AssertUtil.isFalse(TenantRoleTypeEnum.TENANT_ROLE_TYPE_MANAGER.getCode().equals(tenantRole.getType()), "系统管理角色不能修改");

        tenantRole = BeanCopyUtil.copyProperties(tenantRoleEditedRequ, TenantRole::new);
        tenantRole.setUpdateUser(userId);
        boolean update = this.updateById(tenantRole);
        List<Long> tenantFunctionIds = tenantRoleEditedRequ.getTenantFunctionIds();
        if(CollectionUtils.isNotEmpty(tenantFunctionIds)){
            Long id = tenantRole.getId();
            tenantRoleFunctionService.removeRoleFunctionByRoleId(id, userId);
            saveRoleFunction(tenantFunctionIds, id, userId, tenantCode);
        }
        return update;
    }

    @Override
    public Boolean deletedRole(TenantRoleDeletedRequ tenantRoleDeletedRequ, Long userId, String tenantCode) {
        Long id = tenantRoleDeletedRequ.getId();
        TenantUserRole tenantUserRole = userRoleService.getUserRoleByRoleId(id);
        AssertUtil.isNull(tenantUserRole, "角色已绑定用户");

        UpdateWrapper<TenantRole> roleUpdateWrapper = new UpdateWrapper<>();
        roleUpdateWrapper
                .lambda()
                .eq(TenantRole::getId, id)
                .set(TenantRole::getUpdateUser, userId)
                .set(TenantRole::getDeleted, Boolean.TRUE);
        boolean b = this.update(roleUpdateWrapper);
        if(b){
            tenantRoleFunctionService.removeRoleFunctionByRoleId(id, userId);
        }
        return b;
    }

    private void saveRoleFunction(List<Long> tenantFunctionIds, Long id, Long optionUserId, String tenantCode){
        if(CollectionUtils.isEmpty(tenantFunctionIds) || id == null){
            return;
        }
        List<TenantFunction> tenantFunctions = tenantFunctionService.listByIds(tenantFunctionIds);
        List<TenantRoleFunction> tenantRoleFunctions = tenantFunctions.stream().map(tenantFunction -> {
            TenantRoleFunction tenantRoleFunction = new TenantRoleFunction();
            tenantRoleFunction.setTenantFunctionId(tenantFunction.getId());
            tenantRoleFunction.setCreateUser(optionUserId);
            tenantRoleFunction.setUpdateUser(optionUserId);
            tenantRoleFunction.setTenantRoleId(id);
            return tenantRoleFunction;
        }).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(tenantRoleFunctions)){
            tenantRoleFunctionService.saveBatch(tenantRoleFunctions);
        }
    }
}
